<?php

namespace app\web\service;

use app\common\logic\CouponLogic;
use app\common\logic\WxAppLogic;
use app\common\model\commonModel;
use app\common\model\trCache;
use app\common\model\trDriver;
use app\common\model\trSystemSet;
use app\common\model\trUser;
use app\common\model\trUserToken;
use app\common\util\ErrorCode;
use app\common\util\Tools;
use app\web\validate\Login;
use think\facade\Validate;

/**
 * Class Auth
 * @package app\web\service
 * 用户登录服务类
 */
class LoginService
{
    private $returnData;
    private $params;

    public function __construct($data, $params)
    {
        $this->returnData = $data;
        $this->params = $params;
    }

    // 通过code请求微信端获取用户信息和key，然后获取请求token
    public function getLoginTokenByWx(){
        $check = new Login();
        if(!$check->check($this->params, [], "login")){
            $this->returnData = ErrorCode::code("params_error");
            $this->returnData['msg'] = $check->getError();
            return $this->returnData;
        }
        $wxAppConfig = trSystemSet::getValue("wxAppConfig");
        if(empty($wxAppConfig)){
            return ErrorCode::code("config_not_exist", "微信小程序");
        }
        $wxLoginUrl = "https://api.weixin.qq.com/sns/jscode2session?appid={$wxAppConfig["appId"]}&secret={$wxAppConfig["appSecret"]}&js_code={$this->params["code"]}&grant_type=authorization_code";
        $result = Tools::curl($wxLoginUrl, "", []);
        $wxResult = json_decode($result, true);
        if (empty($wxResult)) {
            return ErrorCode::code("customized", "获取session_key及openID时异常，微信内部错误");
        } else {
            if (!empty($wxResult['errcode'])) {
                return ErrorCode::code("customized", "错误代码：$wxResult[errcode]，消息：$wxResult[errmsg]");
            } else {
                $wxResult["nickname"] = $this->emojiFilter($this->params["nickname"]);
                $wxResult["avatar"] = $this->params["avatar"];
                $wxResult["sex"] = $this->params["sex"];
                $token = Tools::createGUID(); //生成token
                $model = new trUser();
                $data = $model->getFields('id,status,mobile', ['openid' => $wxResult['openid'], "mall_id" => request()->mallData["id"]], true, false);
                if(empty($data["mobile"]) || !Validate::isMobile($data["mobile"])){ // 没绑定手机号或者手机号错误
                    if(!empty($data)){
                        $wxResult = array_merge($data, $wxResult);
                    }
                    trCache::saveCache(["key" => $token, "value" => $wxResult, "time" => 300]); //存到缓存和数据库中，下次优先拿缓存
                    $this->returnData["data"] = ["isBindMobile" => false, "token" => $token, "userData" => []];
                }else{ // 已绑定
                    if($data['status'] == '2'){
                        return ErrorCode::code("customized", "用户已被冻结，请联系管理员");
                    }else if($data['status'] == '3'){
                        return ErrorCode::code("customized", "用户已被注销，请联系管理员");
                    }
                    $wxResult["id"] = $data["id"]; //用户ID
                    $wxResult["status"] = $data["status"];
                    if(!$userData = $this->updateUser($wxResult, $token)){
                        return $this->returnData;
                    }
                    $this->returnData["data"] = ["isBindMobile" => true, "token" => $token, "userData" => $userData];
                }
                return $this->returnData;
            }
        }
    }

    // 过滤处理微信昵称中emoji字符
    public function emojiFilter($original_name){
        // Match Emoticons
        $regexEmoticons = '/[\x{1F600}-\x{1F64F}]/u';
        $clean_text = preg_replace($regexEmoticons, '?', $original_name);
        // Match Miscellaneous Symbols and Pictographs
        $regexSymbols = '/[\x{1F300}-\x{1F5FF}]/u';
        $clean_text = preg_replace($regexSymbols, '?', $clean_text);
        // Match Transport And Map Symbols
        $regexTransport = '/[\x{1F680}-\x{1F6FF}]/u';
        $clean_text = preg_replace($regexTransport, '?', $clean_text);
        // Match Miscellaneous Symbols
        $regexMisc = '/[\x{2600}-\x{26FF}]/u';
        $clean_text = preg_replace($regexMisc, '?', $clean_text);
        // Match Dingbats
        $regexDingbats = '/[\x{2700}-\x{27BF}]/u';
        $clean_text = preg_replace($regexDingbats, '?', $clean_text);
        return $clean_text;
    }

    // 绑定手机号，更新或者创建用户
    public function toBindMobile(){
        $check = new Login();
        if(!$check->check($this->params, [], "bind")){
            $this->returnData = ErrorCode::code("params_error");
            $this->returnData['msg'] = $check->getError();
            return $this->returnData;
        }
        $cacheData = trCache::getValue("value", ["key" => $this->params["token"]]);
        if(empty($cacheData)){
            return ErrorCode::code("token_expire");
        }
        $cacheData["mobile"] = $this->params["mobile"];
        $model = new trUser();
        $data = $model->getFields('id', ['mobile' => $cacheData['mobile'], "mall_id" => request()->mallData["id"]], true, false); // 需要查询数据库有没有手机号的用户，有手机号就去掉老账号重新绑定
        if(!empty($data["id"])){
            $model->doUpdate(["mobile" => null], ['id' => $data['id']]);
        }
        $driverModel = new trDriver();
        if($driverModel->getCount(["mobile" => $cacheData["mobile"], "mall_id" => request()->mallData["id"]])){
            $cacheData["userType"] = 1; // 用户绑定司机
            $driverModel->doUpdate(["openid" => $cacheData['openid']], ["mobile" => $cacheData["mobile"], "mall_id" => request()->mallData["id"]]); // 司机绑定微信
        }else if(commonModel::getCount(verifierTable, ["mobile" => $cacheData["mobile"], "mall_id" => request()->mallData["id"]])){
            $cacheData["userType"] = 2; // 用户绑定核销员
            commonModel::toUpdate(verifierTable, ["openid" => $cacheData['openid']], ["mobile" => $cacheData["mobile"], "mall_id" => request()->mallData["id"]]); // 核销员绑定微信
        }
        $registerStatus = 0;  //区别是否新用户获取优惠券
        if(!empty($cacheData["id"])){ // 有用户，但没绑定手机号
            if($cacheData['status'] == '2'){
                return ErrorCode::code("customized", "用户已被冻结，请联系管理员");
            }else if($cacheData['status'] == '3'){
                return ErrorCode::code("customized", "用户已被注销，请联系管理员");
            }
            $userData = $this->updateUser($cacheData, $this->params["token"]);
        }else{ // 没有用户，没绑定手机号
            $registerStatus = 1;
            $userData = $this->createUser($cacheData, $this->params["token"]);
        }
        if(isset($userData["code"])){
            return $userData;
        }
        // 推荐人 推荐了新用户， 则自动领取推荐优惠券
        if($registerStatus && !empty($this->params['sharerId']) && !CouponLogic::addUserCouponByRecommend($this->params['sharerId'], 0, $msg)){
            Tools::writeLog("{$this->params['sharerId']} -- 推荐者获取优惠券失败：".$msg, "couponRecommend.txt");
        }
        $this->returnData["data"] = ["token" => $this->params["token"], "registerStatus" => $registerStatus,"userData" => $userData ? $userData : []];
        trCache::del($this->params["token"]);
        return $this->returnData;
    }

    public function decryptMobile(){
        foreach (["encryptedData", "iv", "code"] as $v) {
            if(!isset($this->params[$v])){
                return ErrorCode::code("params_not_exist", $v);
            }
        }
        $wxAppConfig = trSystemSet::getValue("wxAppConfig");
        $wxLoginUrl = "https://api.weixin.qq.com/sns/jscode2session?appid={$wxAppConfig["appId"]}&secret={$wxAppConfig["appSecret"]}&js_code={$this->params["code"]}&grant_type=authorization_code";
        $result = Tools::curl($wxLoginUrl, "", []);
        $wxResult = json_decode($result, true);
        $aesKey = base64_decode($wxResult["session_key"]);
        if (strlen($this->params["iv"]) != 24) {
            return ErrorCode::code("params_format", "iv");
        }
        $aesIV = base64_decode($this->params["iv"]);
        $aesCipher = base64_decode($this->params["encryptedData"]);
        $result = openssl_decrypt($aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV);
        $dataObj = json_decode($result); // 这是个对象，不是数组
        if ($dataObj == NULL) {
            return ErrorCode::code("customized", "解密失败");
        }
        if ($dataObj->watermark->appid != $wxAppConfig["appId"]) {
            return ErrorCode::code("customized", "解密失败");
        }
        $result = json_decode($result, true);
        $this->returnData["data"] = ["mobile" => $result['purePhoneNumber']];
        return $this->returnData;
    }

    // 更新用户信息
    public function updateUser($wxResult, $token){
        $model = new trUser();
        $userData = [
            'session_key' => $wxResult['session_key'],
            'nickname' => $wxResult['nickname'],
            'avatar' => $wxResult['avatar'],
            'gender' => $wxResult['sex'],
            'unionid' => isset($wxResult["unionid"]) ? $wxResult["unionid"] : "",
            'openid' => $wxResult['openid'],
        ];
        if(isset($wxResult["mobile"])){
            $userData["mobile"] = $wxResult["mobile"];
        }
        if(isset($wxResult["userType"])){ // 1是司机，2核销员
            $userData["user_type"] = $wxResult["userType"];
        }
        $result = $model->doUpdate($userData, ["id" => $wxResult['id']]);
        if (isset($result['code'])) {
            return $result;
        }
        if(!$result){
            return ErrorCode::code("customized", "更新用户失败");
        }
        $ip = Tools::get_client_ip();
        $id = trUserToken::add(["time" => time(), "ip" => $ip, "user_id" => $wxResult["id"], "token" => $token, "mall_id" => request()->mallData["id"]]); // 用户每次登录存放请求token
        if (isset($id['code'])) {
            return $id;
        }
        trCache::saveCache(["key" => "user_login_{$wxResult["id"]}_{$ip}", "value" => $token]); //存到当前用户登录的token
        $data = $model->getFields("id,mall_id,number_id,nickname,gender,mobile,email,avatar,balance,amount,address,status,user_type,register_time", ["id" => $wxResult["id"]], true, false);
        $cacheData = [
            "id" => $wxResult["id"], "openid" => $wxResult["openid"], "status" => $wxResult["status"],
            "sessionKey" => $wxResult["session_key"], "mobile" => $data["mobile"], "mallId" => $data["mallId"]
        ];
        cache("web_" . $token, $cacheData, trUserToken::$cacheTime); // 登录信息放缓存
        return $data;
    }

    // 创建用户
    public function createUser($wxResult, $token){
        $model = new trUser();
        $userData = [
            'session_key' => $wxResult['session_key'],
            'nickname' => $wxResult['nickname'],
            'avatar' => $wxResult['avatar'],
            'gender' => $wxResult['sex'],
            'unionid' => isset($wxResult["unionid"]) ? $wxResult["unionid"] : "",
            'openid' => $wxResult['openid'],
            'register_time' => time(),
        ];
        if(isset($wxResult["userType"])){ // 1是司机，2核销员
            $userData["user_type"] = $wxResult["userType"];
        }
        if(isset($wxResult["mobile"])){
            $userData["mobile"] = $wxResult["mobile"];
        }
        $userId = $model->add($userData, true);
        if (isset($userId['code'])) {
            return $userId;
        }
        if(!$userId){
            return ErrorCode::code("customized", "创建用户失败");
        }
        $ip = Tools::get_client_ip();
        $id = trUserToken::add(["time" => time(), "ip" => $ip, "user_id" => $userId, "token" => $token, "mall_id" => request()->mallData["id"]]); // 用户每次登录存放请求token
        if (isset($id['code'])) {
            return $id;
        }
        trCache::saveCache(["key" => "user_login_{$userId}_{$ip}", "value" => $token]); //存到当前用户登录的token
        $data = $model->getFields("number_id,mall_id,nickname,gender,mobile,email,avatar,balance,amount,address,status,user_type,register_time", ["id" => $userId], true, false);
        $cacheData = ["id" => $userId, "openid" => $wxResult["openid"], "status" => 1, "sessionKey" => $wxResult["session_key"], "mobile" => $data["mobile"], "mallId" => $data["mallId"]];
        $data["genderText"] = $model->getAttrByGender($data["gender"]);
        $data["statusText"] = $model->getAttrByStatus($data["status"]);
        if(isset($this->params["formId"])) {
            WxAppLogic::sendRegisterTpl($wxResult["openid"], $this->params["formId"], $data); // 注册通知
        }
        CouponLogic::addUserCouponByNewLogin($userId); // 发放普通优惠券
        cache("web_" . $token, $cacheData, trUserToken::$cacheTime); //登录信息放缓存
        return $data;
    }

    // 退出登录token
    public function clearToken($userId){
        trUserToken::delByFilter(["token" => $this->params["token"], "mall_id" => request()->mallData["id"]]);
        trCache::del("user_login_{$userId}_".Tools::get_client_ip());
        cache("web_" . $this->params["token"], null);
        $model = new trUser();
        $model->doUpdate(["mobile" => null], ['id' => $userId]);// 退出登录去除绑定手机关系，下次可以用新号绑定
        return true;
    }

    /**
     * @param $token
     * @return bool|mixed
     * 查询数据库
     */
    public static function checkToken($token){
        if (!$userData = cache("web_" . $token)){
            $data = trUserToken::getFields("user_id", ["token" => $token, "mall_id" => request()->mallData["id"]], true, false);
            if(empty($data['userId'])){
                return ErrorCode::code("token_expire");
            }
            $validToken = trCache::getValue("value", ["key" => "user_login_{$data["userId"]}_".Tools::get_client_ip()]);
            if(!empty($validToken) && $token != $validToken){
                return ErrorCode::code("token_expire");
            }
            $userModel = new trUser();
            $userData = $userModel->getFields("id,mall_id,openid,session_key,mobile,status", ["id" => $data["userId"]], true, false);
            cache("web_" . $token, $userData, trUserToken::$cacheTime); // 缓存，把登录的用户信息存起来
        }
        if(empty($userData["mobile"]) || !Validate::isMobile($userData["mobile"])) { // 没绑定手机号或者手机号错误
            return ErrorCode::code("no_bind", "该用户没绑定手机号");
        }
        if($userData['status'] == '2'){
            return ErrorCode::code("customized", "用户已被冻结，请联系管理员");
        }else if($userData['status'] == '3'){
            return ErrorCode::code("customized", "用户已被注销，请联系管理员");
        }
        return $userData;
    }
}